﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Navigation;
using WinForms = System.Windows.Forms;
using System.Threading;
using System.Linq;

namespace EasyMp3Organizer
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		static List<string> mp3Files = new List<string>();
		static List<DirectoryInfo> subDirs = new List<DirectoryInfo>();
		static string mp3Folder;
		string[] audioFilesExtensions = { "*.mp3", "*.wma", "*.m4a" };
		delegate void AppendTextToTextBoxHandler(string textToAppend);
		delegate void ProgressBarInformationHandler(bool progressbarVisible, int percentage);

		public MainWindow()
		{
			InitializeComponent();
		}

		private void lblAbout_RequestNavigate(object sender, RequestNavigateEventArgs e)
		{
			Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
			e.Handled = true;
		}

		private void btnSelectRoot_Click(object sender, RoutedEventArgs e)
		{

			WinForms.FolderBrowserDialog diag = new WinForms.FolderBrowserDialog() { ShowNewFolderButton = false };
			if (diag.ShowDialog() == System.Windows.Forms.DialogResult.OK)
			{
				mp3Files.Clear();
				subDirs.Clear();

				this.txtLog.Clear();
				this.txtMp3Root.Text = diag.SelectedPath;
				mp3Folder = diag.SelectedPath;

				this.txtLog.Clear();
				progressBar.Visibility = System.Windows.Visibility.Hidden;
			}
		}

		private void btnOrganize_Click(object sender, RoutedEventArgs e)
		{
			ThreadPool.QueueUserWorkItem(t =>
			{
				Dispatcher.Invoke(new ProgressBarInformationHandler(SetProgressBarInformation), false, 0);

				ListMp3Files();
				ReallocateMp3Files();
				DeleteEmptyDirectories();

				Dispatcher.Invoke(new AppendTextToTextBoxHandler(AppendTextToTextBox), "Finished.");
				MessageBox.Show("Finished.");
			});
		}

		private static int CalculatePercentage(int current, int total)
		{
			return (int)Math.Round(((double)(current) / (double)total) * 100);
		}

		private void AppendTextToTextBox(string textToAppend)
		{
			this.txtLog.AppendText(textToAppend);
			this.txtLog.ScrollToEnd();
		}

		private void SetProgressBarInformation(bool progressbarVisible, int percentage)
		{
			this.progressBar.Visibility = progressbarVisible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Hidden;
			this.progressBar.Value = percentage;
		}

		private void ListMp3Files()
		{
			if (!string.IsNullOrEmpty(mp3Folder) && Directory.Exists(mp3Folder))
			{
				foreach (string extension in audioFilesExtensions)
					mp3Files.AddRange(Directory.GetFiles(mp3Folder, extension, SearchOption.AllDirectories));
				mp3Files.Sort();

				for (int i = 0; i < mp3Files.Count; i++)
				{
					string textToAppend = "Found file: " + mp3Files[i] + Environment.NewLine;
					Dispatcher.Invoke(new AppendTextToTextBoxHandler(AppendTextToTextBox), textToAppend);

					int progress = CalculatePercentage(i + 1, mp3Files.Count);
					Dispatcher.Invoke(new ProgressBarInformationHandler(SetProgressBarInformation), true, progress);
				}
			}
		}

		private void ReallocateMp3Files()
		{
			if (mp3Files.Count > 0)
			{
				for (int i = 0; i < mp3Files.Count; i++)
				{
					FileInfo fi = new FileInfo(mp3Files[i]);

					TagLib.File f = TagLib.File.Create(mp3Files[i]);
					string artist = "", album = "", trackNr = "", title = "", newDirectory = "", newFileName = "";

					if (f.Tag.Performers.Length > 0)
					{
						if (!string.IsNullOrEmpty(f.Tag.Performers[0])) artist = f.Tag.Performers[0];
						else artist = "Unknown artist";
					}
					else artist = "Unknown artist";

					if (!string.IsNullOrEmpty(f.Tag.Album)) album = f.Tag.Album;

					if (f.Tag.Track != 0) trackNr = f.Tag.Track.ToString("00");

					if (!string.IsNullOrEmpty(f.Tag.Title)) title = f.Tag.Title;
					else title = "Unknown track title";

					string invalidChars = System.Text.RegularExpressions.Regex.Escape(new string(System.IO.Path.GetInvalidFileNameChars()));
					string invalidReStr = string.Format(@"([{0}]*\.+$)|([{0}]+)", invalidChars);

					newDirectory = Path.Combine(mp3Folder, System.Text.RegularExpressions.Regex.Replace(artist, invalidReStr, "_"));
					DirectoryInfo newDirInfo = new DirectoryInfo(newDirectory);
					if (!newDirInfo.Exists)
					{
						try { newDirInfo.Create(); }
						catch { }
					}

					newFileName =
						artist
						+ (!string.IsNullOrEmpty(album) ? "_" + album : "")
						+ (!string.IsNullOrEmpty(trackNr) ? "_" + trackNr : "")
						+ "_" + title
						+ fi.Extension;
					newFileName = System.Text.RegularExpressions.Regex.Replace(newFileName, invalidReStr, "_");

					FileInfo newFi = new FileInfo(Path.Combine(newDirInfo.FullName, newFileName));
					try
					{
						if (fi.FullName != newFi.FullName)
						{
							if (newFi.Exists) newFi.Delete();
							fi.MoveTo(newFi.FullName);
						}
					}
					catch { }

					string textToAppend = string.Format("Moving \"{0}\" to \"{1}\".{2}", fi.FullName, newFi.FullName, Environment.NewLine);
					Dispatcher.Invoke(new AppendTextToTextBoxHandler(AppendTextToTextBox), textToAppend);

					int progress = CalculatePercentage(i + 1, mp3Files.Count);
					Dispatcher.Invoke(new ProgressBarInformationHandler(SetProgressBarInformation), true, progress);
				}
			}
		}

		private void DeleteEmptyDirectories()
		{
			if (!string.IsNullOrEmpty(mp3Folder) && Directory.Exists(mp3Folder))
			{
				DirectoryInfo di = new DirectoryInfo(mp3Folder);
				subDirs.AddRange(di.GetDirectories("*", SearchOption.AllDirectories));
				for (int i = subDirs.Count - 1; i >= 0; i--)
				{
					int totalFiles = 0;

					totalFiles = subDirs[i]
						.GetFiles("*.*", SearchOption.AllDirectories)
						.Where(x => (x.Attributes & FileAttributes.Hidden) == 0)
						.Count();

					if (totalFiles == 0)
					{
						string textToAppend = string.Format("Deleting folder: \"{0}\".{1}", subDirs[i].FullName, Environment.NewLine);
						Dispatcher.Invoke(new AppendTextToTextBoxHandler(AppendTextToTextBox), textToAppend);

						try { subDirs[i].Delete(true); }
						catch { }
					}

					int progress = CalculatePercentage(subDirs.Count - i, subDirs.Count);
					Dispatcher.Invoke(new ProgressBarInformationHandler(SetProgressBarInformation), true, progress);
				}
			}
		}
	}
}
